Adding a search bar to a static site like Eleventy can be tricky because there is no "server" to handle searches. However, we can build a fast, client-side search using a small JSON index and a tiny bit of JavaScript.
1. Create the Search Index
First, we need to create a file that contains all your blog data in a format JavaScript can read. Create a file named search-index.json.njk in your root folder.
File: search-index.json.njk
Code snippet
---
permalink: /search.json
---
[
{% for post in collections.post %}
{
"title": {{ post.data.title | dump | safe }},
"url": {{ post.url | dump | safe }},
"date": "{{ post.date | postDate }}"
}{% if not loop.last %},{% endif %}
{% endfor %}
]
This file generates a /search.json file every time you build your site.
---
2. Add the Search UI to the Sidebar
Go to your _includes/layout.njk and add the search input at the top of your <aside> tag.
Update your <aside>:
HTML
<aside>
<h3>Search</h3>
<input type="text" id="search-input" placeholder="Type to search..." style="width: 100%; padding: 8px; box-sizing: border-box; margin-bottom: 10px;">
<ul id="search-results" class="post-list" style="display: none; background: #f9f9f9; padding: 10px; border: 1px solid #ddd;"></ul>
<hr>
<h3>Archive</h3>
{# ... your existing collapsible tree code ... #}
</aside>
---
3. Add the Search Logic (JavaScript)
Add this script just before the closing </body> tag in your layout.njk. This script fetches the JSON file and filters the results as the user types.
HTML
<script>
const searchInput = document.getElementById('search-input');
const resultsList = document.getElementById('search-results');
let posts = [];
// 1. Fetch the index once
fetch('/search.json')
.then(response => response.json())
.then(data => posts = data);
// 2. Filter on input
searchInput.addEventListener('input', (e) => {
const term = e.target.value.toLowerCase();
resultsList.innerHTML = '';
if (term.length < 2) {
resultsList.style.display = 'none';
return;
}
const filtered = posts.filter(post =>
post.title.toLowerCase().includes(term)
);
if (filtered.length > 0) {
resultsList.style.display = 'block';
filtered.forEach(post => {
const li = document.createElement('li');
li.innerHTML = `<a href="${post.url}">${post.title}</a> <br> <small>${post.date}</small>`;
resultsList.appendChild(li);
});
} else {
resultsList.style.display = 'block';
resultsList.innerHTML = '<li>No matches found</li>';
}
});
</script>
---
How Client-Side Search Works
- The Index: 11ty generates a small list of all your posts (search.json).
- The Fetch: When a visitor loads your site, their browser downloads that tiny JSON file.
- The Instant Filter: As they type, the JavaScript instantly scans that local list. There is no waiting for a server response—it's lightning-fast.
4. Push to Cloudflare
Bash
git add .
git commit -m "Add client-side search"
git push origin main
Your blog is now highly functional! Since we have a search index and an archive, would you like to add an RSS feed so people can subscribe to your blog via their favorite reader?